<?php
/**
 * Created by PHPStorm
 * User: xiest
 * Date: 2021/6/6
 * Email: <939369942@qq.com>
 */

namespace basic\services;

use app\common\repositories\info\InfoRepository;
use app\common\repositories\member\MemberRecordRepository;
use app\common\repositories\member\MemberRepository;
use app\common\repositories\order\OrderRepository;
use EasyWeChat\Factory;
use think\exception\ErrorException;
use think\exception\ValidateException;
use think\facade\Config;
use think\facade\Log;
use think\facade\Route;

class MiniProgramService{

    protected $service;

    protected $config;

    protected $payment = null;

    /**
     * MiniProgramService constructor.
     * @param $config
     */
    public function __construct($config)
    {
        $this->config = $config;
        $this->service = Factory::miniProgram($config);
    }

    public static function create()
    {
        return new self(self::getConfig());
    }

    /**
     * @return \EasyWeChat\MiniProgram\Application
     * User: xiest
     * Date: 2021/10/29
     */
    public function getService()
    {
        return $this->service;
    }


    /**
     * @return \EasyWeChat\Payment\Application
     * @Author: xiest
     * @Date: 2021/9/18 15:20
     */
    public function payment()
    {
        if(!$this->payment){
            $this->payment = Factory::payment(self::getConfig());
        }
        return $this->payment;
    }

    /**
     * @param $openId
     * @param $orderSn
     * @param $fee
     * @param $body
     * @param $attach
     * @param string $tradeType
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \GuzzleHttp\Exception\GuzzleException
     * @Author: xiest
     * @Date: 2021/9/18 13:59
     */
    public function jsPay($openId,$orderSn,$fee,$body,$attach)
    {
        $prepay_id = $this->paymentPrepare($openId,$orderSn,$fee,$body,$attach);
        return $this->formatOrderData($prepay_id);
    }


    public function paymentPrepare($openId,$orderSn,$fee,$body,$attach,$tradeType = 'JSAPI')
    {
        $result = $this->payment()->order->unify([
            'body' => $body,
            'out_trade_no' => $orderSn,
            'total_fee' => $fee,
            'attach'=>$attach,
            //'spbill_create_ip' => '123.12.12.123', // 可选，如不传该参数，SDK 将会自动获取相应 IP 地址
            //'notify_url' => 'https://pay.weixin.qq.com/wxpay/pay.action', // 支付结果通知网址，如果不设置则会使用配置里的默认地址
            'trade_type' => $tradeType, // 请对应换成你的支付方式对应的值类型
            'openid' => $openId,
        ]);

        if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
            return $result['prepay_id'];
        } else {
            if ($result['return_code'] == 'FAIL') {
                throw new ValidateException('微信支付错误返回：' . $result['return_msg']);
            } else if (isset($result['err_code'])) {
                throw new ValidateException('微信支付错误返回：' . $result['err_code_des']);
            } else {
                throw new ValidateException('没有获取微信支付的预支付ID，请重新发起支付!');
            }
        }
    }


    /**
     * 退款
     * @param $orderSn
     * @param $refundOrderSn
     * @param $totalPrice
     * @param $refundPrice
     * @param $refundDesc
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * User: xiest
     * Date: 2021/11/4
     */
    public function payRefund($orderSn,$refundOrderSn,$totalPrice,$refundPrice,$refundDesc)
    {
        $rs = $this->payment()->refund->byOutTradeNumber($orderSn,$refundOrderSn,$totalPrice,$refundPrice,[
            'refund_desc'=>$refundDesc
        ]);

        if($rs['return_code'] == 'SUCCESS' && $rs['result_code'] == 'SUCCESS') return;
        else{
            if($rs['return_code'] == 'FAIL'){
                throw new ValidateException('微信退款错误返回：' . $rs['return_msg']);
            }else if(isset($rs['err_code'])){
                throw new ValidateException('微信退款错误返回：' . $rs['err_code_des']);
            }else{
                throw new ValidateException('微信退款失败');
            }
        }
    }


    public function formatOrderData($prepay_id)
    {
        return $this->payment()->jssdk->bridgeConfig($prepay_id,false);
    }


    /**
     * 小程序支付回调
     * @return \Symfony\Component\HttpFoundation\Response
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
     * @Author: xiest
     * @Date: 2021/9/18 14:07
     */
    public function handleNotify()
    {
        //Log::info('开始回调');

        return $this->payment()->handlePaidNotify(function ($message,$fail){
            if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态，不代表支付状态
                // 用户是否支付成功
                if ($message['result_code']=== 'SUCCESS') {
                    try {
                        if( $message['attach'] == 'info'){
                            app()->make(InfoRepository::class)->paySuccess($message['out_trade_no']);
                        }else if($message['attach'] == 'member'){
                            app()->make(MemberRepository::class)->paySuccess($message['out_trade_no']);
                        }

                        /**@var $make OrderRepository**/
                        /*$make = app()->make(OrderRepository::class);
                        $order = $make->getWhere(['order_sn'=>$message['out_trade_no'],'is_del'=>0]);
                        if($order) $make->paySuccess($order);*/
                        /*event('pay_success_' . $message['attach'], ['order_sn'=>$message['out_trade_no'],'data'=>$message]);*/
                    } catch (\Exception $e) {
                        Log::info('小程序支付回调失败:' . $e->getMessage().'|'.$e->getFile().'|'.$e->getLine());
                        return $fail('通信失败，请稍后再通知我');
                    }
                }
            } else {
                return $fail('通信失败，请稍后再通知我');
            }
            return true;
        });
    }


    public static function getConfig()
    {
        $sysConfig = systemConfig([
            'site_url',
            'miniprogram_app_id','miniprogram_secret',
            'miniprogram_mer_id','miniprogram_mer_key',
            'miniprogram_mer_cert_path','miniprogram_mer_key_path','miniprogram_pay_return_url'
        ]);

        $config['app_id'] = $sysConfig['miniprogram_app_id'];
        $config['secret'] = $sysConfig['miniprogram_secret'];
        $config['mch_id'] = 1653087115;//$sysConfig['miniprogram_mer_id'];
        $config['key'] = "jsdiofjsoidejfosdddddasweda45a4d";//$sysConfig['miniprogram_mer_key'];

        $config['cert_path'] = public_path().'mer_key/apiclient_cert.pem';
        $config['key_path'] = public_path().'mer_key/apiclient_key.pem';
        $config['notify_url'] = env('SITE_URL').Route::buildUrl('AppletsNotice')->build();
        return $config;
    }


    public function getUserInfo($code)
    {
        return $this->service->auth->session($code);
    }

    public function urlScheme($param = [])
    {
        return $this->service->url_scheme->generate($param);
    }


    /**
     * 数据解密
     * @param $sessionKey
     * @param $iv
     * @param $encryptData
     * @return array
     * @throws \EasyWeChat\Kernel\Exceptions\DecryptException
     * User: xiest
     * Date: 2021/6/7
     */
    public function encryptor($sessionKey,$iv,$encryptData)
    {
        return $this->service->encryptor->decryptData($sessionKey,$iv,$encryptData);
    }


    /**
     * 小程序二维码
     * @return \EasyWeChat\MiniProgram\AppCode\Client
     * User: xiest
     * Date: 2021/6/7
     */
    public function appCode()
    {
        return $this->service->app_code;
    }

    public function accessToken()
    {
        return $this->service->access_token;
    }


    /**
     * 发送订阅消息
     * @param String $openId 接收人
     * @param String $templateId 模板ID
     * @param array $data { "key1": { "value": any }, "key2": { "value": any } }
     * @param string|null $link 点击跳转的小程序链接
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \GuzzleHttp\Exception\GuzzleException
     * User: xiest
     * Date: 2021/6/7
     */
    public function sendSubscribeMsg(String $openId,String $templateId,array $data,string $link = null)
    {
        $msg = [
            'template_id' => $templateId, // 所需下发的订阅模板id
            'touser' => $openId,     // 接收者（用户）的 openid
            'page' => $link,       // 点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转。
            'data' => $data
        ];
        return $this->service->subscribe_message->send($msg);
    }




}
